package home.mutant.gauto.generative;

import home.mutant.gauto.utils.ImageUtils;
import home.mutant.gauto.utils.MathUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jenes.chromosome.BitwiseChromosome;
import jenes.population.Fitness;
import jenes.population.Individual;

public class GenerativeFitness extends Fitness<BitwiseChromosome>
{
	List<byte[]> images = new ArrayList<byte[]>();
	List<Integer> numberNeuronsPerLayer;
	private final static int NO_SAMPLES = 1;
	
	@Override
	public void evaluate(Individual<BitwiseChromosome> individual)
	{
		evaluateWithDispersion(individual);
	}
	
	private void evaluateWithDispersion(Individual<BitwiseChromosome> individual)
	{
		int[] imagesRecon = new int[images.size()];
		Arrays.fill(imagesRecon, 0);
		double coincidence = 0;
		for (int i =0;i<images.size()*NO_SAMPLES ;i++)
		{
			Double[] output = WeightsModel.generateSampleNoBias(numberNeuronsPerLayer,individual);
			int max=Integer.MIN_VALUE;
			int indexMax = 0;
			for (int img = 0;img<images.size();img++)
			{
				int tmpCoincidence = coincidence(images.get(img), output);
				if (tmpCoincidence>max)
				{
					max = tmpCoincidence;
					indexMax = img;
				}
			}
			coincidence+=max;
			imagesRecon[indexMax]++;
		}
		double dispersion = MathUtils.standardDev(imagesRecon);
		individual.setScore(coincidence/(images.size()*NO_SAMPLES) - 100*Math.abs(dispersion));
	}
	

	public GenerativeFitness(List<Integer> numberNeuronsPerLayer) throws IOException
	{
		super(true);
		this.numberNeuronsPerLayer = new ArrayList<Integer>(numberNeuronsPerLayer);
		loadImages();
	}
	
	public static int coincidence(byte[] test, Double[] sample)
	{
		int coincidence=0;
		for (int i = 0; i < sample.length; i++)
		{
			if (test[i]==sample[i])
			{
				coincidence+=1;
			}
			else
			{
				coincidence-=1;
			}
		}
		return coincidence;
	}
	private void loadImages() throws IOException
	{
		for(int i=1;i<=8;i++)
		{
			String resourceClass = "/A" +i + ".bmp";
			byte[] image = new byte[100];
			ImageUtils.readResourceImage(resourceClass, image);
			images.add(image);
		}
	}

}
